package net.grandnature.android.morse.decode.example2;

import java.io.IOException;

import shoozhoo.utils.InstrumentWaveFile;
import android.app.Activity;
import android.content.Context;
import android.media.MediaPlayer;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.TextView;

public class MorseDecodeExampleActivity extends Activity implements OnClickListener {
	// ピークかどうかを判断する際に利用する閾値
	public static final double PEEK_THRESHOLD = 0.1;
	// この文字数以上ならエラーにする
	public static final int MAX_NUM = 10;
	// 間隔
	public static final int INTERVAL = 3;
	// ピークの判断に使う係数（適当）
	public static final int PEEK_MOD = 50;

	private static final int[] WAVE_FILES = {R.raw.hello, R.raw.fxcamera, R.raw.egawadesu, R.raw.tel110};
    private Spinner spinner;
    private TextView result;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        initResources();
    }
    private void initResources() {
		spinner = (Spinner) findViewById(R.id.spinner);
		ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
				this, R.array.source, android.R.layout.simple_spinner_item);
		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		spinner.setAdapter(adapter);
		result = (TextView) findViewById(R.id.result);
		Button execute = (Button) findViewById(R.id.execute);
		execute.setOnClickListener(this);
    }
	@Override
	public void onClick(View v) {
		int resId = WAVE_FILES[spinner.getSelectedItemPosition()];
		new SoundPlayerTask(this).execute(resId);
		try {
			result.setText(decodeMorse(resId));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**
	 * 簡易なBPMをしてピークの値を取る
	 * @param data
	 * @return
	 */
	private double getPeek(double[] data, int samplingDataNum) {
		ValueHolder vh = new ValueHolder(samplingDataNum);
		int len = data.length;
		for (int i = 3; i < len-2; i++) {
			if(data[i] <= data[i-1])
				continue;
			if(data[i] <= data[i+1])
				continue;
			if(data[i-2] >= data[i]-PEEK_THRESHOLD)
				continue;
			if(data[i+2] >= data[i]-PEEK_THRESHOLD)
				continue;
			vh.add(data[i]);
		}
		double result = vh.getMedian();
		return result;
	}
	// デバッグ用
	void printSeq(double[] data, int th, int samplingDataNum) {
		ValueHolder vh = new ValueHolder(samplingDataNum);
		int len = data.length;
		boolean    onoff = false;
		StringBuffer sb = new StringBuffer();
		for (int i=0; i < len; i++) {
			if(vh.add(data[i])){
				double quan = vh.getQuantity();
				onoff = quan > th;
				if(onoff) {
					sb.append("o");
				} else {
					sb.append("-");
				}
			}
		}
		Log.v("hoge", sb.toString());
	}
	private String decodeMorse(int resId) throws IOException {
		InstrumentWaveFile iwf = new InstrumentWaveFile(getResources().openRawResource(resId));
		double[] data = SoundDataUtils.convertFromShortArrayToDoubleArray(iwf.get16bitData());
		// TODO ホントはテンポをけいさんしてちゃんとやる
		int samplingDataNum = (resId == R.raw.hello) ? 120 : (resId == R.raw.tel110) ? 180 : 200;
		int peek = (int)(getPeek(data, samplingDataNum) * PEEK_MOD);
		printSeq(data, peek, samplingDataNum);
		return decodeImpl(data, peek, samplingDataNum);
		
	}
	String decodeImpl(double[] data, int peek, int samplingDataNum) {
		boolean on = false;
		boolean mark = false;
		int mark_count = 0;
		int space_count = 0;
		StringBuilder str = new StringBuilder();
		StringBuilder resultStr = new StringBuilder();
		int len = data.length;
		ValueHolder vh = new ValueHolder(samplingDataNum);
		
		for (int i = 0; i < len; i++) {
			if(vh.add(data[i])){
				double quan = vh.getQuantity();
				// マークとスペースの反転
				on = quan > peek;
				if (on != mark) {
					mark = on;
					if (mark) {
						mark_count = space_count = 0;
					} else {
						space_count = 0;
					}
				}
				if (mark) {
					mark_count++;
				} else {
					space_count++;
					if (mark_count > 0 && (space_count > INTERVAL)) {
						// 1はトン（ドットor短点）、3はツー（ダッシュor長点）、短点:長点は一般的には1:3らしい。
						str.append(mark_count > INTERVAL * 2 ? '3' : '1');
						mark_count = 0;
						if(str.length() > MAX_NUM) {
							resultStr.append("too many char");
							return resultStr.toString();
						}
					}
					// 文字の終わり判断
					if (space_count > INTERVAL * 2) {
						if (str.length() > 0) {
							resultStr.append("[" + str + "]\n");
							resultStr.append("[" + MorseMapping.decodeSignalToChar(str.toString()) + "]\n");
							str = new StringBuilder();
						}
					}
				}
			}
		}
		return resultStr.toString();
	}
	private class SoundPlayerTask extends AsyncTask<Integer, Integer, Exception> {
		private final Context context;
		private MediaPlayer player;

		public SoundPlayerTask(Context context) {
			this.context = context;
		}
		@Override
		protected Exception doInBackground(Integer... params) {
			try {
				player = MediaPlayer.create(context, params[0].intValue());
				player.start();
			} catch (Exception e) {
				return e;
			}
			return null;
		}
	}
}